import os
import sys
import wx
import time
import traceback
import platform
import fnmatch
import tempfile

from subprocess import Popen, PIPE

from constants import _defaultIgnoreList, ENOENT, EPIPE


def FormatFileSize(size):
    
    for x in ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']:

        if size < 1024.0:
            return "%3.2f %s" % (size, x)

        size /= 1024.0

        
def FormatTrace(etype, value, trace):
    """Formats the given traceback
    
    **Returns:**

    *  Formatted string of traceback with attached timestamp
    
    **Note:**

    *  from Editra.dev_tool
    """
    
    exc = traceback.format_exception(etype, value, trace)
    exc.insert(0, "*** %s ***%s" % (now(), os.linesep))
    return "".join(exc)
            

def FormatTime(startTime):

    currTime = time.time()
    mins, secs = divmod(currTime - startTime, 60)
    hours, mins = divmod(mins, 60)
    elapsed = '%02dm:%02ds' % (mins, secs)

    return elapsed    


def EnvironmentInfo(version):
    """
    Returns a string of the systems information.
    
    
    **Returns:**

    *  System information string
    
    **Note:**

    *  from Editra.dev_tool
    """

    info = list()
    info.append("#---- Notes ----#")
    info.append("Please provide additional information about the crash here")
    info.extend(["", "", ""])
    info.append("#---- System Information ----#")
    info.append("Namespace Diff Tool Version: %s" % version)
    info.append("Operating System: %s" % wx.GetOsDescription())
    if sys.platform == 'darwin':
        info.append("Mac OSX: %s" % platform.mac_ver()[0])
    info.append("Python Version: %s" % sys.version)
    info.append("wxPython Version: %s" % wx.version())
    info.append("wxPython Info: (%s)" % ", ".join(wx.PlatformInfo))
    info.append("Python Encoding: Default=%s  File=%s" % \
                (sys.getdefaultencoding(), sys.getfilesystemencoding()))
    info.append("wxPython Encoding: %s" % wx.GetDefaultPyEncoding())
    info.append("System Architecture: %s %s" % (platform.architecture()[0], \
                                                platform.machine()))
    info.append("Byte order: %s" % sys.byteorder)
    info.append("Frozen: %s" % str(getattr(sys, 'frozen', 'False')))
    info.append("#---- End System Information ----#")

    return os.linesep.join(info)


def now():
    """ Returns the current time formatted. """

    t = time.localtime(time.time())
    st = time.strftime("%d %B %Y @ %H:%M:%S", t)
    
    return st


def shortNow():
    """ Returns the current time formatted. """
    
    t = time.localtime(time.time())
    st = time.strftime("%H:%M:%S", t)

    return st


def MakeInheritanceDiagram(code):

    # graphviz expects UTF-8 by default
    if isinstance(code, unicode):
        code = code.encode('utf-8')

    dot_args = ['dot']
    outfn = tempfile.mktemp('.png')

    dot_args.extend(['-Tpng', '-o' + outfn])
    dot_args.extend(['-Tcmapx', '-o%s.map' % outfn])
    
    try:
        
        p = Popen(dot_args, stdout=PIPE, stdin=PIPE, stderr=PIPE)

    except OSError, err:

        if err.errno != ENOENT:   # No such file or directory
            raise

        msg = 'dot command "dot" cannot be run (needed for graphviz output), check your PATH setting'
        return msg, 'Error'
    
    try:
        # Graphviz may close standard input when an error occurs,
        # resulting in a broken pipe on communicate()
        stdout, stderr = p.communicate(code)

    except OSError, err:

        # in this case, read the standard output and standard error streams
        # directly, to get the error message(s)
        stdout, stderr = p.stdout.read(), p.stderr.read()
        p.wait()
        
    if p.returncode != 0:
        msg = 'dot exited with error:\n[stderr]\n%s\n[stdout]\n%s' % (stderr, stdout)
        return msg, 'Error'
    
    return outfn, None


class NDTMode(object):

    def __init__(self, package_class, other_package_class=None, filter=u'',
                 selectedItem=None, expansionState=(), ignoreList=_defaultIgnoreList):
        
        self.package_class = package_class
        self.other_package_class = other_package_class
        self.filter = filter
        self.selectedItem = selectedItem
        self.expansionState = expansionState
        self.ignoreList = ignoreList[:]


    def Equals(self, other):

        keys = self.__dict__.keys()
        
        for key in keys:
            me, you = getattr(self, key), getattr(other, key)
            if me != you:
                return False

        return True            

